-
Notifications
You must be signed in to change notification settings - Fork 117
Add no-std support #184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add no-std support #184
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As an over-arching observation I would be quite interested in seeing what a breaking change from current AsRef<OsStr> to some in-crate trait (e.g. trait ToFilename) would look like. That way we'd be able to control the types available between non-std and std contexts without adding all these additional constructor functions.
src/os/unix/mod.rs
Outdated
| where | ||
| P: AsRef<OsStr>, | ||
| { | ||
| //TODO Why is this an option?, we have Library::this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's because in the OS-specific bindings I closely match the underlying OS API in case users wanted to use/had a use-case for e.g. dlopen(NULL, FLAGS) in this case. Library::this exists but it does not allow specifying arbitrary flags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not intend to commit, this, my bad. I added a lot of comments to understand your code for myself and removed all those. I will remove this.
src/error.rs
Outdated
| #[cfg(not(feature = "std"))] | ||
| pub struct WindowsError(pub(crate) i32); | ||
|
|
||
| #[cfg(feature = "std")] | ||
| pub struct WindowsError(pub(crate) std::io::Error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO we can unconditionally store just the error code and potentially explore replicating some of the niceties for the std::io::Error (such as the error description text via FormatMessageW) ourselves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would break any software that relies on cause() to return io::Error.
I dont care about that, if you want it done this way then I shall do so.
|
Concerning your idea of a trait to replace AsRef< OsStr > that would work, but it would likely be a full on breaking change. If you want me to do it with a trait then that is fine, but I would recommend a major version bump in this case. |
|
This crate is still pre-1.0 so breaking changes are still not a huge deal. As an example we also have #174 in the pipeline. |
|
I see, in that case I will try implement this with 2 traits. One called "ToFilename" and one called "ToSymbolName" that would make the mentioned pr obsolete. Have you decided what we should do in regards to the msrv bump due to error in core? Sidenote: I would prefer it if this pr could be merged in a reasonable timeframe after you are satisfied. |
We're making a breaking change anyway, so there is no reason to not bump the MSRV. Especially when we're doing so to a version that has been released a while ago. This is a good opportunity to proactively set MSRV to maybe 1.86 or 1.88 or something of the sort. |
|
In that case I will let you handle the msrv bump outside of this pr. I will bump it to the minimum required version. You can then bump it again to whatever you desire. |
|
@nagisa I am satisfied, please tell me what else must be changed for you to be able to merge this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking quite good so far! I appreciate you spending time to prototype this out.
src/lib.rs
Outdated
| #[cfg(feature = "std")] | ||
| use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; | ||
| #[cfg(feature = "std")] | ||
| use std::ffi::{OsStr, OsString}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: these uses could be moved to inside the function and/or references to them replaced by fully-qualified paths in order to avoid these getting accidental non-local use in future development more obviously.
(Of course the CI would catch such instances, but why defer when we can have rustc complain about it during cargo check.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ci didnt catch this, I will move it to the function anyways
src/as_filename.rs
Outdated
| /// - CString &CString &CStr | ||
| /// - OsString &OsString &OsStr | ||
| /// - PathBuf &PathBuf &Path | ||
| /// - &[u8] assumes utf8 data! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On unixes neither a file path nor the symbol name are required to be a valid utf-8. They can often be arbitrary bytes which is why we have the OsString in libstd. IMO &[u8] should not require utf-8 encoding (as produced by str::as_bytes) on unix systems.
Documentation nit: the implementers of the trait already appear at the bottom of generated documentation. I don't think we should list the specific types, other than perhaps mentioning in passing that most common types you might want to use are supported. Specific implementations with their special requirements (such as use of &[u8] on windows platforms or those imposed by &[u16]) should probably document those requirements on the trait implementation itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For any utf-8 and utf-16 requirements I would also defer/link directly to the relevant methods on String or similar. Something along the lines of
/// The buffer must contain valid data for the purposes of [`String::from_utf16`].
or similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we drop the utf-8 requirement we should similarly drop the utf-16 requirement in my opinion. I have never seen a filename which cannot be described as utf-8. Sure you can construct such OsStrings but you can always express that same path with utf-8 to my knowledge. Alas I dont want to argue on this technicality that completely irrelevant for me. I will drop the utf-8 and utf-16 requirements and just check for zero byte element/ending and ensure that no interior 0 element exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For Windows utf-16 (or wtf-8) are required for their *W suffixed APIs, though, and their *A style APIs are kinda a footgun. So it makes sense to me to have the utf-16 requirement for/on Windows.
I've seen non-utf8 paths on unixes in the past. Depends heavily on the locale used (which for east-asian countries still is often not utf-8.)
Speaking of &[u8] and &[u16] and cross-platform support: I'm not sure how we'd convert a &[u16] to &[u8] when &[u16] is not specified to be utf-16. At the same time the reverse is also unclear – how to convert arbitrary non-utf8 &[u8] to a Windows path? So I think these implementations need to be made available conditionally on the target (i.e. only have &[u8] for unix and &[u16] for windows), or we should omit them entirely and rely on OsStr(ing)/Path(Buf) for people to provide these weird paths (they can still use regular string in std-less environments.) Similarly to &[u8], CString is also unclear with regards to paths on Windows.
I'd say lets have implementations for Path{,Buf}, OsStr{,ing} (fully featured but std-only) and str{,ing} (utf-8 only but works without std) for now and we can add further options later as needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think u8 and u16 slices cannot be done cross platform. In my most recent local version that I made earlier I have as you mentioned just made the impl different.
On unix u16 must be utf-16, on windows not. On windows u8 must be utf8 on unix not. I will commit it later.
I think we should keep u8 and u16 slice around but comment that they behave differently on each platform for no std to be able to call this with arbitrary data. Otherwise no std would not be able to call it with a non str.
Alternative is implementing it for c_void ptr and just passing that in which pushes this complexit to the user. (But also all of the danger) I dont care either way.
I recommend you take a look at my latest version that I will commit later this evening and then we can decide what to do here. I think I resolved all your other pain points.
src/as_filename.rs
Outdated
| /// | ||
| /// The data can be assumed to be formatted like the windows `LPCWSTR` if it is at all valid. | ||
| /// | ||
| #[allow(unused)] //Posix doesnt use this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think libloading being a semi-foundational library should avoid compiling dead code on platforms that don't use it. Should probably cfg-out the irrelevant methods. Could also explore having just one method that changes in signature based on the target (i.e. make the method names same.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considers this, but I didnt like 1 function taking a different FnOnce depending on os.
Sure we can cfg-if it out, thats preferable in my opinion.
src/as_symbol_name.rs
Outdated
| /// - CString &CString &CStr | ||
| /// - OsString &OsString &OsStr | ||
| /// - PathBuf &PathBuf &Path | ||
| /// - &[u8] assumes utf8 data! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we should especially be not requiring utf-8, as symbols can be pretty much anything.
Similarly, I don't think it makes much sense to implement these traits for OsString or PathBuf. That's pretty weird type to want to use for a symbol name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ill remove the std section of the impl then. I was pretty tired when I copied that over and didnt think much about it. Yeah a path in a symbol name would be beyond weird your correct.
Ill also get rid of the utf-8/utf-16 requirement
src/as_symbol_name.rs
Outdated
| /// | ||
| /// This function is guaranteed to error or invoke the `FnOnce` parameter, | ||
| /// and if called, return whatever the `FnOnce` returns. | ||
| /// | ||
| /// The pointer parameter to the `FnOnce` is guaranteed to point to a valid 0 terminated | ||
| /// c-string. | ||
| /// | ||
| /// The data the pointer points to is guaranteed to live until the `FnOnce` returns. | ||
| /// | ||
| /// The data can be assumed to be 0 terminated utf-8 on unix or 0 terminated wtf-8 on windows. | ||
| /// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't really need some of these properties (utf-8/wtf-8) in order to look up a symbol name. Should only require a bare minimum that's required for the specific task. I think the requirement of not having interior null pointers (other than for the last byte) has also been lost.
I'm curious, though, is there any reason why you chose to use the closure approach here over retaining the signature from cstr_cow_from_bytes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The closure approach makes the lifetime guarantee of the pointer obvious and trivial to describe.
I saw many "odd" drop() that ensured lifetimes in the old impl. I didnt like that.
I will get rid of the last element in this doc block.
|
|
||
| impl<T> AsSymbolName for T where T: private::AsSymbolNameSeal {} | ||
|
|
||
| impl private::AsSymbolNameSeal for &str { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that the only method of this trait takes a reference already, these traits should either be implemented for str, String (&String being superfluous, right?). We can then add an impl<S: AsSymbolName> AsSymbolName for &S to cover all the nested references. Similar to AsRef.
Or the method should be made to take self by value and the trait should continue being implemented for all the types it currently is for. Where the owned value is available (String, OsString, etc.) we can then make the implementation a bit more optimal by pushing a 0 byte to the end of the string without reallocating it whole in cstr_cow_from_bytes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your correct, I will change it so that it takes impl AsSymbol name just like it is for the filename. This was a oversight.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Edit: Where did you see that I take a AsRef of the trait?
pub unsafe fn get<T>(&self, symbol: impl AsSymbolName) -> Result<Symbol<'_, T>, Error> { ... }This is how usage currently looks, this is not AsRef?
Edit2: I now understand what you said. I will fix it.
…e implementations to use less utf-8/16.
|
alright latest changes are using self instead of &self in the trait. I was also able to more or less unify the Cow logic for both u8 and u16 where we check for the 0 element Is there anything else you would like adjusted? |
|
Merged in 4b98285 |
As discussed in #183
There are a few things I would like to mention.
Concerning the error_in_core MSRV bump, if that is unacceptable then we have 2 options.
I don't care about the error impl personally so its your choice.
I have not tested this yet on my Windows computer and will only have access to one in about a Weeks time,
so yeah this is not quite yet ready to merge but It is at a state where you can take a look at it and tell me what you think. I will also get to fixing up the documentation once I have more time.